// Alvaro, 8/5/2011

// CLASS hardwareIO:
// This class takes care of the INPUT OUTPUT LOW LEVEL ROUTINES:
// (1) ADC (readout lock in amp output)
// (2) DAC (control mirrors and red laser)
// (3) control green laser
// (4) Set Prescalers (for lock in reference generation)

// REM: LCD not used, but if you want, use Serial3

#ifndef hardwareIO_h
#define hardwareIO_h

#include "WProgram.h"
#include <SPI.h>
// NOTE: the SPI library uses the following pins, but we don't have to set them and inputs or outputs (this is done when the library is initialized, which is done by pre-instantiation. 
#define SCK_PIN   52 //SPI Clock
#define MISO_PIN  50 //SPI input (data comming from DAC, here not connected) 
#define MOSI_PIN  51 //SPI output (data going to DAC)

//**** CHIP SELECT pins for MP4922 DAC (mirrors and red laser)
// VERY IMPORTANT: the chip select for the DACs should be different from the default SPI "SS" pin (Slave Select), which is 53 by default (and will be used by the Ethernet Shield). 
#define CS_DAC_MIRRORS   37 //Chip Select of the first DAC (mirrors)
#define CS_DAC_REDLASER   36 //Chip Select of the second DAC (red Laser)
// Also, IT IS VERY IMPORANT TO CORRECTLY SET THE PORT VALUE when setting the CS to high or low, if not using digitalWrite!!! 
// For instance, on the ArduinoMEGA, digitalWrite(53, LOW) is equivalent but much slower than this: PORTB &= B11111110;
// In fact, on the MEGA we have: 
// PORTA: 22 to 29 
// PORTB: 0,1,2,3 to pins 53, 52, 51 and 50. 
// PORTC: 30 to 37  (PC0 is 37, PC6 is 30) <----- WE WILL USE first two bits of PORTC

//**** LOCKIN amplifier:
#define LOCKIN_PIN 8 // NOTE: this pin is not used explicitly unless we use FastAnalogRead(int analogpin) - we don't use analogRead here, but the function FastAnalogReadPin0() or FastAnalogRead(int analogpin).
#define I_Volts_SAT 5 // this is 5V (the saturation voltage for the APD+LockIn+ADC, being it the arduino (when in normal mode) or the SPI. This saturation voltage could be different for each mode!?
#define EIGHT_BITS 0 // readout mode (not a pin): this will use SPI based ADC (external chip) 
#define TEN_BITS 1   // redout mode (not a pin): this will use the standard analogRead() method

//**** RED laser (rem: the red laser power will be controlled by tge SPI DAC, value in mW)
#define MAX_AD_RED 4095 // 10 bits SPI interface (output: 0-5 volts)
#define MAX_RedLaserPower 3 // in mW  - measuring the power RIGHT AFTER THE MIRRORS
#define MIN_RedLaserPower 0 // in mW
#define Volts_to_AD_RED 819 //=(MAX_AD_RED/5.0) 
#define mW_to_Volts_RED 1.667 //(5.0/(MAX_RedLaserPower-MIN_RedLaserPower)) //  we assume linear relation from volts to mW
#define mW_to_AD_RED 1365 // (mW_to_Volts_RED*Volts_to_AD_RED)

//**** GREEN laser: 
#define greenLaserPin 22 // just use digital IO (HIGH/LOW)
// Nothing to do (HIGH or LOW for the time being...)

//**** MIRRORS: 
//The DAC is 12 bytes capable (Max=4096), but we will limit this a little. 
#define MAX_AD_MIRRORS 4000 // Absolute maximum for the SPI voltage (5V). This is for checking hardware compliance, but max and min angles can be defined for X and Y in each LivingSpot instance.
#define MIN_AD_MIRRORS 0
// We assume that the center of the mirror is at MAX_AD_MIRRORS/2 = 2000:
#define CENTER_AD_MIRROR_X 2000 // This MUST BE the direction of the photodetector. 
#define CENTER_AD_MIRROR_Y 2000 // This MUST BE the direction of the photodetector.
#define MAX_DEG_MIRROR_X 20 // Angular value when AD mirror value is MAX_AD_MIRRORS (same for X and Y). ATTN! this value must be calibrated! otherwise cartesian coordinates will be wrong...
#define MIN_DEG_MIRROR_X -20 // Angular value when AD mirror value is 0
#define MAX_DEG_MIRROR_Y 20
#define MIN_DEG_MIRROR_Y -20
// REM: we have for instance, if Az is in degrees and assuming a linear relationship between voltage and degrees: 
// AD value for X mirror =  (Az-MIN_DEG_MIRROR_X)/(MAX_DEG_MIRROR_X-MIN_DEG_MIRROR_X)*MAX_AD_MIRRORS
//float deg_to_AD_MIRROR_X=1.0*(MAX_DEG_MIRROR_X-MIN_DEG_MIRROR_X)/(MAX_AD_MIRRORS-MIN_AD_MIRRORS);
//float deg_to_AD_MIRROR_Y=1.0*(MAX_DEG_MIRROR_Y-MIN_DEG_MIRROR_Y)/(MAX_AD_MIRRORS-MIN_AD_MIRRORS);
//float AD_to_Deg_MIRROR_X=1.0*(MAX_AD_MIRRORS-MIN_AD_MIRRORS)/(MAX_DEG_MIRROR_X-MIN_DEG_MIRROR_X);
//float AD_to_Deg_MIRROR_Y=1.0*(MAX_AD_MIRRORS-MIN_AD_MIRRORS)/(MAX_DEG_MIRROR_Y-MIN_DEG_MIRROR_Y);
//float deg_to_AD_MIRROR=1.0/AD_to_Deg_MIRROR_X;// this will be used for radius update

//**** BUTTONS: 
// NOTE: we will use interrupt 0, activated by rising edge on INTERRUPT_BUTTON_PIN (2), and then we will read all the bits of the
// eight buttons (actually, we use only 6 for the time being). 
#define INTERRUPT_READ_BUTTONS 0 //THIS IS PIN 2 !!! 
#define interruptButtonPin 3
#define BUTTON_BYTE_PORT PINA

// **** POTENTIOMETERS: 
#define potA_pin 1 // analog inputs
#define potB_pin 2
//float valuePotA, valuePotB; //Will be normalized.
// Note: the value of the potentiometers is scanned when we press a particular BUTTON 

// **** PIN to MANUALLY change modes (DIGITAL)
#define pinSwitch 2 

//potentiometer to set the FIXED threshold (ANALOG pin)
//#define pinAnalogPot 1  
//int potValue;
//int potFixThreshold;

// **** BUZZER (PWM): 
#define buzzer_pin 6 // (PWM output)

// **** REFERENCE SIGNAL: 
#define testPin_OC1A 11 // this is, output compare pin OC1A //connected to CK2 = lockIn clock
#define testPin_OC1B 12 // this is, output compare pin OC1B //connected to CK1 = laser clock
#define testPin_OC1C 13

#include "OSCClass.h"
extern OSCMessage recMes;
extern OSCMessage sendMes;
extern OSCClass osc;

// ==================================================================================================================================================================

class HardwareIO {
public:

        // not nice being here, but useful for the time being:
        void scanArea_OSC(void);
        void scanArea_Serial(int resolution);

	void init(void);

	int analogReadMode; //  analog read mode (could be private). Can be 8_BITS, 10_BITS 
	void setAnalogReadMode(int);
	float LockInRead_Volts(); 
	int LockInRead_AD(); 
        float LockInAD_to_Volts(int); 

	// buttons readout function (interrupt based): 
	void readButtons();
	byte buttonByte;
	boolean processButton; // will set to true when a button is pressed (it must be set to 0 after processing button input, probably in the main program)

	// potentiometer values (normalized)
	float valuePotA, valuePotB; 
	float readPotA(); 
	float readPotB(); 

	// SPI control for DAC for mirrors and red laser power (low level): 
        void writeOutX(int value);
        void writeOutY(int value);
        void writeOutR(int value);
	
	// mirror degree-to-AD units conversion factors: 
	float AD_to_Deg_MIRROR_X;//=1.0*(MAX_DEG_MIRROR_X-MIN_DEG_MIRROR_X)/(MAX_AD_MIRRORS-MIN_AD_MIRRORS);
	float AD_to_Deg_MIRROR_Y;//=1.0*(MAX_DEG_MIRROR_Y-MIN_DEG_MIRROR_Y)/(MAX_AD_MIRRORS-MIN_AD_MIRRORS);

	// Mirror position:
	void setMirrorX_Deg(float _Az); 
	void setMirrorY_Deg(float _El);
	void setMirrorX_AD(int _AzAD); 
	void setMirrorY_AD(int _ElAD);
	void setMirrorsXY_AD(int _xAD, int _yAD); 
	void setMirrorsCenter();
	void getAnglesFromAD(float &Az, float &El, int _xAD, int _yAD); 
	//void setZoneDelimiters(...) // this could be here, instead on the LivingSpot class

	// Red laser:
	void setRedPower_AD(int powerAD);// from 0 to MAX_RED_POWER
	void setRedPower_mW(float powermW); 
        
	// Green laser: 
	void setGreenPower(boolean); // HIGH or LOW

        void setupPWM();
        /* IN ADVANCED HARDWARE: 
	// init PWM for reference generation:
	void initPWM();
	// reference signal: 
	void setRefFreq(int);
	void incRefFreq(int inc=1);
	void decRefFreq(int dec=1);
       */

	// buzzer: 
	void setBuzzerFreq(int); 
	void setBuzzer(boolean state);
	void buzzerBip(int timebip=300, int times=1);

	// LCD output (could make a class, but c'mon): 
	void clearLCD();
	void clearLine(int line);
	void displayLineLCD(char *string, int line);
	void displayLineLCD(float num, int line); // we can also use with integer, by forcing the type: (float)number
	void displayLineLCD(byte num, int line); 

	float refFreq; // could be private

        // custom fast reading ADC functions (8 bit resolution only):
      	byte FastAnalogReadPin0();
        byte FastAnalogReadPin8();
     
private:
	


};

extern HardwareIO IO;

#endif

